package HLogger

import (
	"fmt"
	"frame/utils/DateUtils"
	"frame/utils/FileUtils"
	"frame/utils/StringUtils"
	"strconv"
	"frame/utils/ServerInfoUtils"
	"time"
	"runtime"
	"strings"
)

const APPENDTYPE_CONSOLE="CONSOLE"
const APPENDTYPE_ALLFILE="ALLFILE"
const APPENDTYPE_TXNFILE="TXNFILE"

const parseLayoutStat_none = 0
const parseLayoutStat_star = 1
const parseLayoutStat_inne = 2
const parseLayoutStat_end = 3

type HLoggerAppender struct{
	appendtype string
	rootpath string
	rootname string
	subpath string
	name string
	layout string
	splitbydate bool
}

type TxnContext struct {
	Txnid string
	Expandinfo map[string]string
}

type HLoggerAppendeInter interface {
	Append(s string,txnContext TxnContext)
	ParseLayout(s string,txnContext TxnContext)
}

func (hla HLoggerAppender)Append(txnContext TxnContext,s string){
	if(hla.appendtype==APPENDTYPE_CONSOLE){
		fmt.Print(hla.ParseLayout(txnContext,s))
	}
	if(hla.appendtype==APPENDTYPE_ALLFILE){
		var message = hla.ParseLayout(txnContext,s)
		var logfile = ""
		if(hla.splitbydate){
			logfile = hla.rootpath+FileUtils.GetFileSeparator()+DateUtils.GetCurrDate()+FileUtils.GetFileSeparator()+hla.rootname+".log"
		}else{
			logfile = hla.rootpath+FileUtils.GetFileSeparator()+hla.rootname+".log"
		}
		FileUtils.AppendMessageFile(message,logfile)
	}
	if(hla.appendtype==APPENDTYPE_TXNFILE){
		var message = hla.ParseLayout(txnContext,s)
		var logfile = ""
		if(hla.splitbydate){
			logfile = hla.rootpath+FileUtils.GetFileSeparator()+DateUtils.GetCurrDate()+FileUtils.GetFileSeparator()+hla.subpath+FileUtils.GetFileSeparator()+hla.name+".log"
		}else{
			logfile = hla.rootpath+FileUtils.GetFileSeparator()+hla.rootname+".log"
		}
		FileUtils.AppendMessageFile(message,logfile)
	}
}
func (hla HLoggerAppender)ParseLayout(txnContext TxnContext,s string)(string){
	var layout_slice = []byte(hla.layout)
	var result = make([]byte,0,4096)
	var stat int = parseLayoutStat_none;
	var currstarPos = 0;
	var currtoken= []byte("");
	//此段性能需要优化，包括参数，性能，内存
	for i:=0;i<len(layout_slice);i++{
 		if(stat == parseLayoutStat_none&&layout_slice[i]!='%'){
			result = append(result,layout_slice[i])
			continue
		}else{
			//等于百分号，或者在一个百分号代表的串中
			if(stat==parseLayoutStat_none && layout_slice[i]=='%'){
				//刚进入一个匹配
				stat=parseLayoutStat_star
				currstarPos = i
			}
			if(stat==parseLayoutStat_star&&i==currstarPos+1&&layout_slice[i]!='%'){
				stat=parseLayoutStat_inne
				currtoken = append(currtoken, layout_slice[i])
			}
			if(stat==parseLayoutStat_inne&&i==currstarPos+2&&layout_slice[i]!='{'){
				stat=parseLayoutStat_end
				i--
			}
			if(stat==parseLayoutStat_inne&&i==currstarPos+2&&layout_slice[i]=='{'){
				currtoken = append(currtoken, layout_slice[i])
			}
			if(stat==parseLayoutStat_inne&&i>currstarPos+2&&layout_slice[i]!='}'){
				currtoken = append(currtoken, layout_slice[i])
			}
			if(stat==parseLayoutStat_inne&&i>currstarPos+2&&layout_slice[i]=='}'){
				currtoken = append(currtoken, layout_slice[i])
				stat=parseLayoutStat_end
			}
			if(stat==parseLayoutStat_inne&&i==len(layout_slice)-1){
				stat=parseLayoutStat_end
			}

		}
		if(stat==parseLayoutStat_end){
			result = append(result,[]byte(getMessage(txnContext,currtoken,s))...)
			//result = append(result,layout_slice[i])
			//fmt.Println(string(currtoken))
			currtoken=[]byte("")
			stat=parseLayoutStat_none
		}
	}
	return string(result)
}

func getMessage( txnContext TxnContext,currtoken []byte,s string)(string){

	if(currtoken[0]=='T'){
		return StringUtils.FillString(txnContext.Txnid,'0',8,false)
	}
	if(currtoken[0]=='P'){
		return txnContext.Expandinfo["loglevel"]
	}
	if(currtoken[0]=='i'){
		var length,_ = strconv.Atoi(string(currtoken[2:len(currtoken)-1]))
		var ip,_ = ServerInfoUtils.GetIP()
		return StringUtils.FillString(ip,' ',length,false)
	}
	if(currtoken[0]=='d'){
		var param = string(currtoken[2:len(currtoken)-1])
		return time.Now().Format(param)
	}
	if(currtoken[0]=='f'){
		var length,_ = strconv.Atoi(string(currtoken[2:len(currtoken)-1]))
		//pc,file,line,ok = runtime.Caller(0)//获得第0层的调用的函数值
		//此处的层级由具体调用设置。目前为：
		// 目标
		// ->Hlogger.Info
		// ->hla.Append(txnContext,v)
		// ->hla.ParseLayout(txnContext,s)
		// ->getMessage( txnContext TxnContext,currtoken []byte,s string)(string)
		// 因此，从0开始，为4
		pc,file,line,_ := runtime.Caller(4)
		var filelastName = string(file[strings.LastIndex(file,"/")+1:])
		//var filelastName = file
		f := runtime.FuncForPC(pc).Name() //package.func
		funcname := f[strings.Index(f,".")+1:]
		return StringUtils.FillString(filelastName+":"+funcname+":"+StringUtils.FillString(strconv.Itoa(line),'0',4,false),' ',length,false)
	}
	if(currtoken[0]=='m'){
		return s
	}
	if(currtoken[0]=='n'){
		return "\r\n"
	}
	return ""

}

const DEFAUsLT_layout = "[%T][%P][%i{14}][%d{yyyyMMdd HHmmss,SSS}][%f{25}] %m%n"